#ifndef STACK_H_

#define STACK_H_

#include "status.h"
#include <iostream>
using namespace std;

template<typename T>
class Stack
{
private:
	struct Node
	{
		T data;
		Node * prior;
		Node * next;
	};
	Node * top;
	int length;
public:
	Stack();
	~Stack();
	Status InitStack();
	Status DestroyStack();
	Status ClearStack();
	bool StackEmpty() const;
	int StackLength() const;
	Status GetTop(T & e) const;
	Status Push(const T & e);
	Status Pop(T & e);
	Status StackTraverse() const;
};

template<typename T>
Stack<T>::Stack() : length(0)
{
	this->top = new Node;
	this->top->prior = nullptr;
	this->top->next = nullptr;
}

template<typename T>
Stack<T>::~Stack()
{
	Node * t_tmp = this->top;
	while (t_tmp != nullptr)
	{
		Node * del_tmp = t_tmp;
		t_tmp = t_tmp->next;
		delete del_tmp;
	}
	this->length = 0;
}

template<typename T>
Status Stack<T>::InitStack()
{
	this->top = new Node;
	this->top->prior = nullptr;
	this->top->next = nullptr;
	this->length = 0;
}

template<typename T>
Status Stack<T>::DestroyStack()
{
	Node * t_tmp = this->top;
	while (t_tmp != nullptr)
	{
		Node * del_tmp = t_tmp;
		t_tmp = t_tmp->next;
		delete del_tmp;
	}
	this->length = 0;

	return OK;
}

template<typename T>
Status Stack<T>::ClearStack()
{
	Node * t_tmp = this->top->next;
	this->top->next = nullptr;
	while (t_tmp != nullptr)
	{
		Node * del_tmp = t_tmp;
		t_tmp = t_tmp->next;
		delete del_tmp;
	}
	this->length = 0;

	return OK;
}

template<typename T>
bool Stack<T>::StackEmpty() const
{
	return this->length == 0;
}

template<typename T>
int Stack<T>::StackLength() const
{
	return this->length;
}

template<typename T>
Status Stack<T>::GetTop(T & e) const
{
	if (StackEmpty())
		return ERROR;

	e = this->top->next->data;
	return OK;
}

template<typename T>
Status Stack<T>::Push(const T & e)
{
	Node * newNode = new Node;
	newNode->data = e;
	newNode->prior = this->top;
	newNode->next = this->top->next;
	this->top->next = newNode;
	++this->length;

	return OK;
}

template<typename T>
Status Stack<T>::Pop(T & e)
{
	if (StackEmpty())
		return ERROR;

	e = this->top->next->data;
	Node * del_tmp = this->top->next;
	this->top->next = del_tmp->next;
	delete del_tmp;
	--this->length;

	return OK;
}

template<typename T>
Status Stack<T>::StackTraverse() const
{
	if (StackEmpty())
		return ERROR;

	const Node * t_tmp = this->top->next;
	while (t_tmp != nullptr)
	{
		cout << t_tmp->data << endl;
		t_tmp = t_tmp->next;
	}

	return OK;
}

#endif